package org.zebra.captcha.picture;

import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.spring.SpringUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.zebra.cache.util.RedisUtil;
import org.zebra.captcha.CaptchaHandler;

import java.time.Duration;

/**
 * 图片验证码处理器
 *
 * @author zhanghongbin
 */
// @AllArgsConstructor
// @NoArgsConstructor
public class PictureCaptchaHandler implements CaptchaHandler<PictureCaptchaVo> {

    @Autowired
    private PictureCaptchaProperties pictureCaptchaProperties;

    private int expirationTime;

    public PictureCaptchaHandler(int expirationTime) {
        this.expirationTime = expirationTime;
    }

    @Override
    public PictureCaptchaVo build(String name) {
        PictureCaptchaVo pictureCaptchaVo = new PictureCaptchaVo();
        boolean enable = pictureCaptchaProperties.isEnabled();
        if (!enable) {
            pictureCaptchaVo.setEnabled(false);
            return pictureCaptchaVo;
        }
        String verifyKey = CAPTCHA_KEY + name;
        // 生成验证码
        PictureCaptchaType captchaType = pictureCaptchaProperties.getType();
        boolean isMath = PictureCaptchaType.MATH == captchaType;
        Integer length = isMath ? pictureCaptchaProperties.getNumberLength() : pictureCaptchaProperties.getCharLength();
        CodeGenerator codeGenerator = ReflectUtil.newInstance(captchaType.getClazz(), length);
        AbstractCaptcha captcha =
                SpringUtil.getBean(pictureCaptchaProperties.getCategory().getClazz());
        captcha.setGenerator(codeGenerator);
        captcha.createCode();
        // 如果是数学验证码，使用SpEL表达式处理验证码结果
        String code = captcha.getCode();
        if (isMath) {
            ExpressionParser parser = new SpelExpressionParser();
            Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
            code = exp.getValue(String.class);
        }
        // 有效期2分钟
        RedisUtil.setCacheObject(
                RedisUtil.getRedisTemplate(), verifyKey, code, Duration.ofMinutes(this.expirationTime));
        pictureCaptchaVo.setUuid(name);
        pictureCaptchaVo.setImg(captcha.getImageBase64());
        return pictureCaptchaVo;
    }

    @Override
    public boolean check(String name, String code) {
        String verifyKey = CAPTCHA_KEY + StringUtils.defaultString(name, "");
        String captcha = RedisUtil.getCacheObject(RedisUtil.getRedisTemplate(), verifyKey);
        RedisUtil.delete(RedisUtil.getRedisTemplate(), verifyKey);
        if (captcha == null) {
            return false;
        }
        return code.equalsIgnoreCase(captcha);
    }
}
